home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Common / src / d3dutil.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  22.7 KB  |  695 lines

  1. //-----------------------------------------------------------------------------
  2. // File: D3DUtil.cpp
  3. //
  4. // Desc: Shortcut macros and functions for using DX objects
  5. //
  6. //
  7. // Copyright (c) 1997-2001 Microsoft Corporation. All rights reserved
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #include <tchar.h>
  11. #include <stdio.h>
  12. #include "D3DUtil.h"
  13. #include "DXUtil.h"
  14. #include "D3DX8.h"
  15.  
  16.  
  17.  
  18.  
  19. //-----------------------------------------------------------------------------
  20. // Name: D3DUtil_InitMaterial()
  21. // Desc: Initializes a D3DMATERIAL8 structure, setting the diffuse and ambient
  22. //       colors. It does not set emissive or specular colors.
  23. //-----------------------------------------------------------------------------
  24. VOID D3DUtil_InitMaterial( D3DMATERIAL8& mtrl, FLOAT r, FLOAT g, FLOAT b,
  25.                            FLOAT a )
  26. {
  27.     ZeroMemory( &mtrl, sizeof(D3DMATERIAL8) );
  28.     mtrl.Diffuse.r = mtrl.Ambient.r = r;
  29.     mtrl.Diffuse.g = mtrl.Ambient.g = g;
  30.     mtrl.Diffuse.b = mtrl.Ambient.b = b;
  31.     mtrl.Diffuse.a = mtrl.Ambient.a = a;
  32. }
  33.  
  34.  
  35.  
  36.  
  37. //-----------------------------------------------------------------------------
  38. // Name: D3DUtil_InitLight()
  39. // Desc: Initializes a D3DLIGHT structure, setting the light position. The
  40. //       diffuse color is set to white; specular and ambient are left as black.
  41. //-----------------------------------------------------------------------------
  42. VOID D3DUtil_InitLight( D3DLIGHT8& light, D3DLIGHTTYPE ltType,
  43.                         FLOAT x, FLOAT y, FLOAT z )
  44. {
  45.     ZeroMemory( &light, sizeof(D3DLIGHT8) );
  46.     light.Type        = ltType;
  47.     light.Diffuse.r   = 1.0f;
  48.     light.Diffuse.g   = 1.0f;
  49.     light.Diffuse.b   = 1.0f;
  50.     D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &D3DXVECTOR3(x, y, z) );
  51.     light.Position.x   = x;
  52.     light.Position.y   = y;
  53.     light.Position.z   = z;
  54.     light.Range        = 1000.0f;
  55. }
  56.  
  57.  
  58.  
  59.  
  60. //-----------------------------------------------------------------------------
  61. // Name: D3DUtil_CreateTexture()
  62. // Desc: Helper function to create a texture. It checks the root path first,
  63. //       then tries the DXSDK media path (as specified in the system registry).
  64. //-----------------------------------------------------------------------------
  65. HRESULT D3DUtil_CreateTexture( LPDIRECT3DDEVICE8 pd3dDevice, TCHAR* strTexture,
  66.                                LPDIRECT3DTEXTURE8* ppTexture, D3DFORMAT d3dFormat )
  67. {
  68.     // Get the path to the texture
  69.     TCHAR strPath[MAX_PATH];
  70.     DXUtil_FindMediaFile( strPath, strTexture );
  71.  
  72.     // Create the texture using D3DX
  73.     return D3DXCreateTextureFromFileEx( pd3dDevice, strPath, 
  74.                 D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, d3dFormat, 
  75.                 D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 
  76.                 D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 0, NULL, NULL, ppTexture );
  77. }
  78.  
  79.  
  80.  
  81.  
  82. //-----------------------------------------------------------------------------
  83. // Name: D3DUtil_SetColorKey()
  84. // Desc: Changes all texels matching the colorkey to transparent, black.
  85. //-----------------------------------------------------------------------------
  86. HRESULT D3DUtil_SetColorKey( LPDIRECT3DTEXTURE8 pTexture, DWORD dwColorKey )
  87. {
  88.     // Get colorkey's red, green, and blue components
  89.     DWORD r = ((dwColorKey&0x00ff0000)>>16);
  90.     DWORD g = ((dwColorKey&0x0000ff00)>>8);
  91.     DWORD b = ((dwColorKey&0x000000ff)>>0);
  92.  
  93.     // Put the colorkey in the texture's native format
  94.     D3DSURFACE_DESC d3dsd;
  95.     pTexture->GetLevelDesc( 0, &d3dsd );
  96.     if( d3dsd.Format == D3DFMT_A4R4G4B4 )
  97.         dwColorKey = 0xf000 + ((r>>4)<<8) + ((g>>4)<<4) + (b>>4);
  98.     else if( d3dsd.Format == D3DFMT_A1R5G5B5 )
  99.         dwColorKey = 0x8000 + ((r>>3)<<10) + ((g>>3)<<5) + (b>>3);
  100.     else if( d3dsd.Format != D3DFMT_A8R8G8B8 )
  101.         return E_FAIL;
  102.  
  103.     // Lock the texture
  104.     D3DLOCKED_RECT  d3dlr;
  105.     if( FAILED( pTexture->LockRect( 0, &d3dlr, 0, 0 ) ) )
  106.         return E_FAIL;
  107.  
  108.     // Scan through each pixel, looking for the colorkey to replace
  109.     for( DWORD y=0; y<d3dsd.Height; y++ )
  110.     {
  111.         for( DWORD x=0; x<d3dsd.Width; x++ )
  112.         {
  113.             if( d3dsd.Format==D3DFMT_A8R8G8B8 )
  114.             {
  115.                 // Handle 32-bit formats
  116.                 if( ((DWORD*)d3dlr.pBits)[d3dsd.Width*y+x] == dwColorKey )
  117.                     ((DWORD*)d3dlr.pBits)[d3dsd.Width*y+x] = 0x00000000;
  118.             }
  119.             else
  120.             {
  121.                 // Handle 16-bit formats
  122.                 if( ((WORD*)d3dlr.pBits)[d3dsd.Width*y+x] == dwColorKey )
  123.                     ((WORD*)d3dlr.pBits)[d3dsd.Width*y+x] = 0x0000;
  124.             }
  125.         }
  126.     }
  127.  
  128.     // Unlock the texture and return OK.
  129.     pTexture->UnlockRect(0);
  130.     return S_OK;
  131. }
  132.  
  133.  
  134.  
  135.  
  136. //-----------------------------------------------------------------------------
  137. // Name: D3DUtil_CreateVertexShader()
  138. // Desc: Assembles and creates a file-based vertex shader
  139. //-----------------------------------------------------------------------------
  140. HRESULT D3DUtil_CreateVertexShader( LPDIRECT3DDEVICE8 pd3dDevice, 
  141.                                     TCHAR* strFilename, DWORD* pdwVertexDecl,
  142.                                     DWORD* pdwVertexShader )
  143. {
  144.     LPD3DXBUFFER pCode;
  145.     TCHAR        strPath[MAX_PATH];
  146.     HRESULT      hr;
  147.  
  148.     // Get the path to the vertex shader file
  149.     DXUtil_FindMediaFile( strPath, strFilename );
  150.  
  151.     // Assemble the vertex shader file
  152.     if( FAILED( hr = D3DXAssembleShaderFromFile( strPath, 0, NULL, &pCode, NULL ) ) )
  153.         return hr;
  154.  
  155.     // Create the vertex shader
  156.     hr = pd3dDevice->CreateVertexShader( pdwVertexDecl, 
  157.                                          (DWORD*)pCode->GetBufferPointer(),
  158.                                          pdwVertexShader, 0 );
  159.     pCode->Release();
  160.     return hr;
  161. }
  162.  
  163.  
  164.  
  165.  
  166. //-----------------------------------------------------------------------------
  167. // Name: D3DUtil_GetCubeMapViewMatrix()
  168. // Desc: Returns a view matrix for rendering to a face of a cubemap.
  169. //-----------------------------------------------------------------------------
  170. D3DXMATRIX D3DUtil_GetCubeMapViewMatrix( DWORD dwFace )
  171. {
  172.     D3DXVECTOR3 vEyePt   = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  173.     D3DXVECTOR3 vLookDir;
  174.     D3DXVECTOR3 vUpDir;
  175.  
  176.     switch( dwFace )
  177.     {
  178.         case D3DCUBEMAP_FACE_POSITIVE_X:
  179.             vLookDir = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
  180.             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  181.             break;
  182.         case D3DCUBEMAP_FACE_NEGATIVE_X:
  183.             vLookDir = D3DXVECTOR3(-1.0f, 0.0f, 0.0f );
  184.             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  185.             break;
  186.         case D3DCUBEMAP_FACE_POSITIVE_Y:
  187.             vLookDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  188.             vUpDir   = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
  189.             break;
  190.         case D3DCUBEMAP_FACE_NEGATIVE_Y:
  191.             vLookDir = D3DXVECTOR3( 0.0f,-1.0f, 0.0f );
  192.             vUpDir   = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
  193.             break;
  194.         case D3DCUBEMAP_FACE_POSITIVE_Z:
  195.             vLookDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
  196.             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  197.             break;
  198.         case D3DCUBEMAP_FACE_NEGATIVE_Z:
  199.             vLookDir = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
  200.             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  201.             break;
  202.     }
  203.  
  204.     // Set the view transform for this cubemap surface
  205.     D3DXMATRIX matView;
  206.     D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookDir, &vUpDir );
  207.     return matView;
  208. }
  209.  
  210.  
  211.  
  212.  
  213. //-----------------------------------------------------------------------------
  214. // Name: D3DUtil_GetRotationFromCursor()
  215. // Desc: Returns a quaternion for the rotation implied by the window's cursor
  216. //       position.
  217. //-----------------------------------------------------------------------------
  218. D3DXQUATERNION D3DUtil_GetRotationFromCursor( HWND hWnd,
  219.                                               FLOAT fTrackBallRadius )
  220. {
  221.     POINT pt;
  222.     RECT  rc;
  223.     GetCursorPos( &pt );
  224.     GetClientRect( hWnd, &rc );
  225.     ScreenToClient( hWnd, &pt );
  226.     FLOAT sx = ( ( ( 2.0f * pt.x ) / (rc.right-rc.left) ) - 1 );
  227.     FLOAT sy = ( ( ( 2.0f * pt.y ) / (rc.bottom-rc.top) ) - 1 );
  228.     FLOAT sz;
  229.  
  230.     if( sx == 0.0f && sy == 0.0f )
  231.         return D3DXQUATERNION( 0.0f, 0.0f, 0.0f, 1.0f );
  232.  
  233.     FLOAT d1 = 0.0f;
  234.     FLOAT d2 = sqrtf( sx*sx + sy*sy );
  235.  
  236.     if( d2 < fTrackBallRadius * 0.70710678118654752440 ) // Inside sphere
  237.         sz = sqrtf( fTrackBallRadius*fTrackBallRadius - d2*d2 );
  238.     else                                                 // On hyperbola
  239.         sz = (fTrackBallRadius*fTrackBallRadius) / (2.0f*d2);
  240.  
  241.     // Get two points on trackball's sphere
  242.     D3DXVECTOR3 p1( sx, sy, sz );
  243.     D3DXVECTOR3 p2( 0.0f, 0.0f, fTrackBallRadius );
  244.  
  245.     // Get axis of rotation, which is cross product of p1 and p2
  246.     D3DXVECTOR3 vAxis;
  247.     D3DXVec3Cross( &vAxis, &p1, &p2);
  248.  
  249.     // Calculate angle for the rotation about that axis
  250.     FLOAT t = D3DXVec3Length( &(p2-p1) ) / ( 2.0f*fTrackBallRadius );
  251.     if( t > +1.0f) t = +1.0f;
  252.     if( t < -1.0f) t = -1.0f;
  253.     FLOAT fAngle = 2.0f * asinf( t );
  254.  
  255.     // Convert axis to quaternion
  256.     D3DXQUATERNION quat;
  257.     D3DXQuaternionRotationAxis( &quat, &vAxis, fAngle );
  258.     return quat;
  259. }
  260.  
  261.  
  262.  
  263.  
  264. //-----------------------------------------------------------------------------
  265. // Name: D3DUtil_SetDeviceCursor
  266. // Desc: Gives the D3D device a cursor with image and hotspot from hCursor.
  267. //-----------------------------------------------------------------------------
  268. HRESULT D3DUtil_SetDeviceCursor( LPDIRECT3DDEVICE8 pd3dDevice, HCURSOR hCursor,
  269.                                  BOOL bAddWatermark )
  270. {
  271.     HRESULT hr = E_FAIL;
  272.     ICONINFO iconinfo;
  273.     BOOL bBWCursor;
  274.     LPDIRECT3DSURFACE8 pCursorBitmap = NULL;
  275.     HDC hdcColor = NULL;
  276.     HDC hdcMask = NULL;
  277.     HDC hdcScreen = NULL;
  278.     BITMAP bm;
  279.     DWORD dwWidth;
  280.     DWORD dwHeightSrc;
  281.     DWORD dwHeightDest;
  282.     COLORREF crColor;
  283.     COLORREF crMask;
  284.     UINT x;
  285.     UINT y;
  286.     BITMAPINFO bmi;
  287.     COLORREF* pcrArrayColor = NULL;
  288.     COLORREF* pcrArrayMask = NULL;
  289.     DWORD* pBitmap;
  290.     HGDIOBJ hgdiobjOld;
  291.  
  292.     ZeroMemory( &iconinfo, sizeof(iconinfo) );
  293.     if( !GetIconInfo( hCursor, &iconinfo ) )
  294.         goto End;
  295.  
  296.     if (0 == GetObject((HGDIOBJ)iconinfo.hbmMask, sizeof(BITMAP), (LPVOID)&bm))
  297.         goto End;
  298.     dwWidth = bm.bmWidth;
  299.     dwHeightSrc = bm.bmHeight;
  300.  
  301.     if( iconinfo.hbmColor == NULL )
  302.     {
  303.         bBWCursor = TRUE;
  304.         dwHeightDest = dwHeightSrc / 2;
  305.     }
  306.     else 
  307.     {
  308.         bBWCursor = FALSE;
  309.         dwHeightDest = dwHeightSrc;
  310.     }
  311.  
  312.     // Create a surface for the fullscreen cursor
  313.     if( FAILED( hr = pd3dDevice->CreateImageSurface( dwWidth, dwHeightDest, 
  314.         D3DFMT_A8R8G8B8, &pCursorBitmap ) ) )
  315.     {
  316.         goto End;
  317.     }
  318.  
  319.     pcrArrayMask = new DWORD[dwWidth * dwHeightSrc];
  320.  
  321.     ZeroMemory(&bmi, sizeof(bmi));
  322.     bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
  323.     bmi.bmiHeader.biWidth = dwWidth;
  324.     bmi.bmiHeader.biHeight = dwHeightSrc;
  325.     bmi.bmiHeader.biPlanes = 1;
  326.     bmi.bmiHeader.biBitCount = 32;
  327.     bmi.bmiHeader.biCompression = BI_RGB;
  328.  
  329.     hdcScreen = GetDC( NULL );
  330.     hdcMask = CreateCompatibleDC( hdcScreen );
  331.     if( hdcMask == NULL )
  332.     {
  333.         hr = E_FAIL;
  334.         goto End;
  335.     }
  336.     hgdiobjOld = SelectObject(hdcMask, iconinfo.hbmMask);
  337.     GetDIBits(hdcMask, iconinfo.hbmMask, 0, dwHeightSrc, 
  338.         pcrArrayMask, &bmi, DIB_RGB_COLORS);
  339.     SelectObject(hdcMask, hgdiobjOld);
  340.  
  341.     if (!bBWCursor)
  342.     {
  343.         pcrArrayColor = new DWORD[dwWidth * dwHeightDest];
  344.         hdcColor = CreateCompatibleDC( GetDC( NULL ) );
  345.         if( hdcColor == NULL )
  346.         {
  347.             hr = E_FAIL;
  348.             goto End;
  349.         }
  350.         SelectObject(hdcColor, iconinfo.hbmColor);
  351.         GetDIBits(hdcColor, iconinfo.hbmColor, 0, dwHeightDest, 
  352.             pcrArrayColor, &bmi, DIB_RGB_COLORS);
  353.     }
  354.  
  355.     // Transfer cursor image into the surface
  356.     D3DLOCKED_RECT lr;
  357.     pCursorBitmap->LockRect( &lr, NULL, 0 );
  358.     pBitmap = (DWORD*)lr.pBits;
  359.     for( y = 0; y < dwHeightDest; y++ )
  360.     {
  361.         for( x = 0; x < dwWidth; x++ )
  362.         {
  363.             if (bBWCursor)
  364.             {
  365.                 crColor = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
  366.                 crMask = pcrArrayMask[dwWidth*(dwHeightSrc-1-y) + x];
  367.             }
  368.             else
  369.             {
  370.                 crColor = pcrArrayColor[dwWidth*(dwHeightDest-1-y) + x];
  371.                 crMask = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
  372.             }
  373.             if (crMask == 0)
  374.                 pBitmap[dwWidth*y + x] = 0xff000000 | crColor;
  375.             else
  376.                 pBitmap[dwWidth*y + x] = 0x00000000;
  377.  
  378.             // It may be helpful to make the D3D cursor look slightly 
  379.             // different from the Windows cursor so you can distinguish 
  380.             // between the two when developing/testing code.  When
  381.             // bAddWatermark is TRUE, the following code adds some
  382.             // small grey "D3D" characters to the upper-left corner of
  383.             // the D3D cursor image.
  384.             if( bAddWatermark && x < 12 && y < 5 )
  385.             {
  386.                 // 11.. 11.. 11.. .... CCC0
  387.                 // 1.1. ..1. 1.1. .... A2A0
  388.                 // 1.1. .1.. 1.1. .... A4A0
  389.                 // 1.1. ..1. 1.1. .... A2A0
  390.                 // 11.. 11.. 11.. .... CCC0
  391.  
  392.                 const WORD wMask[5] = { 0xccc0, 0xa2a0, 0xa4a0, 0xa2a0, 0xccc0 };
  393.                 if( wMask[y] & (1 << (15 - x)) )
  394.                 {
  395.                     pBitmap[dwWidth*y + x] |= 0xff808080;
  396.                 }
  397.             }
  398.         }
  399.     }
  400.     pCursorBitmap->UnlockRect();
  401.  
  402.     // Set the device cursor
  403.     if( FAILED( hr = pd3dDevice->SetCursorProperties( iconinfo.xHotspot, 
  404.         iconinfo.yHotspot, pCursorBitmap ) ) )
  405.     {
  406.         goto End;
  407.     }
  408.  
  409.     hr = S_OK;
  410.  
  411. End:
  412.     if( iconinfo.hbmMask != NULL )
  413.         DeleteObject( iconinfo.hbmMask );
  414.     if( iconinfo.hbmColor != NULL )
  415.         DeleteObject( iconinfo.hbmColor );
  416.     if( hdcScreen != NULL )
  417.         ReleaseDC( NULL, hdcScreen );
  418.     if( hdcColor != NULL )
  419.         DeleteDC( hdcColor );
  420.     if( hdcMask != NULL )
  421.         DeleteDC( hdcMask );
  422.     SAFE_DELETE_ARRAY( pcrArrayColor );
  423.     SAFE_DELETE_ARRAY( pcrArrayMask );
  424.     SAFE_RELEASE( pCursorBitmap );
  425.     return hr;
  426. }
  427.  
  428.  
  429.  
  430.  
  431. //-----------------------------------------------------------------------------
  432. // Name: D3DXQuaternionUnitAxisToUnitAxis2
  433. // Desc: Axis to axis quaternion double angle (no normalization)
  434. //       Takes two points on unit sphere an angle THETA apart, returns
  435. //       quaternion that represents a rotation around cross product by 2*THETA.
  436. //-----------------------------------------------------------------------------
  437. inline D3DXQUATERNION* WINAPI D3DXQuaternionUnitAxisToUnitAxis2
  438. ( D3DXQUATERNION *pOut, const D3DXVECTOR3 *pvFrom, const D3DXVECTOR3 *pvTo)
  439. {
  440.     D3DXVECTOR3 vAxis;
  441.     D3DXVec3Cross(&vAxis, pvFrom, pvTo);    // proportional to sin(theta)
  442.     pOut->x = vAxis.x;
  443.     pOut->y = vAxis.y;
  444.     pOut->z = vAxis.z;
  445.     pOut->w = D3DXVec3Dot( pvFrom, pvTo );
  446.     return pOut;
  447. }
  448.  
  449.  
  450.  
  451.  
  452. //-----------------------------------------------------------------------------
  453. // Name: D3DXQuaternionAxisToAxis
  454. // Desc: Axis to axis quaternion 
  455. //       Takes two points on unit sphere an angle THETA apart, returns
  456. //       quaternion that represents a rotation around cross product by theta.
  457. //-----------------------------------------------------------------------------
  458. inline D3DXQUATERNION* WINAPI D3DXQuaternionAxisToAxis
  459. ( D3DXQUATERNION *pOut, const D3DXVECTOR3 *pvFrom, const D3DXVECTOR3 *pvTo)
  460. {
  461.     D3DXVECTOR3 vA, vB;
  462.     D3DXVec3Normalize(&vA, pvFrom);
  463.     D3DXVec3Normalize(&vB, pvTo);
  464.     D3DXVECTOR3 vHalf(vA + vB);
  465.     D3DXVec3Normalize(&vHalf, &vHalf);
  466.     return D3DXQuaternionUnitAxisToUnitAxis2(pOut, &vA, &vHalf);
  467. }
  468.  
  469.  
  470.  
  471.  
  472. //-----------------------------------------------------------------------------
  473. // Name:
  474. // Desc:
  475. //-----------------------------------------------------------------------------
  476. CD3DArcBall::CD3DArcBall()
  477. {
  478.     D3DXQuaternionIdentity( &m_qDown );
  479.     D3DXQuaternionIdentity( &m_qNow );
  480.     D3DXMatrixIdentity( &m_matRotation );
  481.     D3DXMatrixIdentity( &m_matRotationDelta );
  482.     D3DXMatrixIdentity( &m_matTranslation );
  483.     D3DXMatrixIdentity( &m_matTranslationDelta );
  484.     m_bDrag = FALSE;
  485.     m_fRadiusTranslation = 1.0f;
  486.     m_bRightHanded = FALSE;
  487. }
  488.  
  489.  
  490.  
  491.  
  492. //-----------------------------------------------------------------------------
  493. // Name:
  494. // Desc:
  495. //-----------------------------------------------------------------------------
  496. VOID CD3DArcBall::SetWindow( int iWidth, int iHeight, float fRadius )
  497. {
  498.     // Set ArcBall info
  499.     m_iWidth  = iWidth;
  500.     m_iHeight = iHeight;
  501.     m_fRadius = fRadius;
  502. }
  503.  
  504.  
  505.  
  506.  
  507. //-----------------------------------------------------------------------------
  508. // Name:
  509. // Desc:
  510. //-----------------------------------------------------------------------------
  511. D3DXVECTOR3 CD3DArcBall::ScreenToVector( int sx, int sy )
  512. {
  513.     // Scale to screen
  514.     FLOAT x   = -(sx - m_iWidth/2)  / (m_fRadius*m_iWidth/2);
  515.     FLOAT y   =  (sy - m_iHeight/2) / (m_fRadius*m_iHeight/2);
  516.  
  517.     if( m_bRightHanded )
  518.     {
  519.         x = -x;
  520.         y = -y;
  521.     }
  522.  
  523.     FLOAT z   = 0.0f;
  524.     FLOAT mag = x*x + y*y;
  525.  
  526.     if( mag > 1.0f )
  527.     {
  528.         FLOAT scale = 1.0f/sqrtf(mag);
  529.         x *= scale;
  530.         y *= scale;
  531.     }
  532.     else
  533.         z = sqrtf( 1.0f - mag );
  534.  
  535.     // Return vector
  536.     return D3DXVECTOR3( x, y, z );
  537. }
  538.  
  539.  
  540.  
  541.  
  542. //-----------------------------------------------------------------------------
  543. // Name:
  544. // Desc:
  545. //-----------------------------------------------------------------------------
  546. VOID CD3DArcBall::SetRadius( FLOAT fRadius )
  547. {
  548.     m_fRadiusTranslation = fRadius;
  549. }
  550.  
  551.  
  552.  
  553.  
  554. //-----------------------------------------------------------------------------
  555. // Name:
  556. // Desc:
  557. //-----------------------------------------------------------------------------
  558. LRESULT CD3DArcBall::HandleMouseMessages( HWND hWnd, UINT uMsg, WPARAM wParam,
  559.                                           LPARAM lParam )
  560. {
  561.     static int         iCurMouseX;      // Saved mouse position
  562.     static int         iCurMouseY;
  563.     static D3DXVECTOR3 s_vDown;         // Button down vector
  564.  
  565.     // Current mouse position
  566.     int iMouseX = LOWORD(lParam);
  567.     int iMouseY = HIWORD(lParam);
  568.  
  569.     switch( uMsg )
  570.     {
  571.         case WM_RBUTTONDOWN:
  572.         case WM_MBUTTONDOWN:
  573.             // Store off the position of the cursor when the button is pressed
  574.             iCurMouseX = iMouseX;
  575.             iCurMouseY = iMouseY;
  576.             return TRUE;
  577.  
  578.         case WM_LBUTTONDOWN:
  579.             // Start drag mode
  580.             m_bDrag = TRUE;
  581.             s_vDown = ScreenToVector( iMouseX, iMouseY );
  582.             m_qDown = m_qNow;
  583.             return TRUE;
  584.  
  585.         case WM_LBUTTONUP:
  586.             // End drag mode
  587.             m_bDrag = FALSE;
  588.             return TRUE;
  589.  
  590.         case WM_MOUSEMOVE:
  591.             // Drag object
  592.             if( MK_LBUTTON&wParam )
  593.             {
  594.                 if( m_bDrag )
  595.                 {
  596.                     // recompute m_qNow
  597.                     D3DXVECTOR3 vCur = ScreenToVector( iMouseX, iMouseY );
  598.                     D3DXQUATERNION qAxisToAxis;
  599.                     D3DXQuaternionAxisToAxis(&qAxisToAxis, &s_vDown, &vCur);
  600.                     m_qNow = m_qDown;
  601.                     m_qNow *= qAxisToAxis;
  602.                     D3DXMatrixRotationQuaternion(&m_matRotationDelta, &qAxisToAxis);
  603.                 }
  604.                 else
  605.                     D3DXMatrixIdentity(&m_matRotationDelta);
  606.                 D3DXMatrixRotationQuaternion(&m_matRotation, &m_qNow);
  607.                 m_bDrag = TRUE;
  608.             }
  609.             else if( (MK_RBUTTON&wParam) || (MK_MBUTTON&wParam) )
  610.             {
  611.                 // Normalize based on size of window and bounding sphere radius
  612.                 FLOAT fDeltaX = ( iCurMouseX-iMouseX ) * m_fRadiusTranslation / m_iWidth;
  613.                 FLOAT fDeltaY = ( iCurMouseY-iMouseY ) * m_fRadiusTranslation / m_iHeight;
  614.  
  615.                 if( wParam & MK_RBUTTON )
  616.                 {
  617.                     D3DXMatrixTranslation( &m_matTranslationDelta, -2*fDeltaX, 2*fDeltaY, 0.0f );
  618.                     D3DXMatrixMultiply( &m_matTranslation, &m_matTranslation, &m_matTranslationDelta );
  619.                 }
  620.                 else  // wParam & MK_MBUTTON
  621.                 {
  622.                     D3DXMatrixTranslation( &m_matTranslationDelta, 0.0f, 0.0f, 5*fDeltaY );
  623.                     D3DXMatrixMultiply( &m_matTranslation, &m_matTranslation, &m_matTranslationDelta );
  624.                 }
  625.  
  626.                 // Store mouse coordinate
  627.                 iCurMouseX = iMouseX;
  628.                 iCurMouseY = iMouseY;
  629.             }
  630.             return TRUE;
  631.     }
  632.  
  633.     return FALSE;
  634. }
  635.  
  636.  
  637.  
  638.  
  639. //-----------------------------------------------------------------------------
  640. // Name:
  641. // Desc:
  642. //-----------------------------------------------------------------------------
  643. CD3DCamera::CD3DCamera()
  644. {
  645.     // Set attributes for the view matrix
  646.     SetViewParams( D3DXVECTOR3(0.0f,0.0f,0.0f), D3DXVECTOR3(0.0f,0.0f,1.0f),
  647.                    D3DXVECTOR3(0.0f,1.0f,0.0f) );
  648.  
  649.     // Set attributes for the projection matrix
  650.     SetProjParams( D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
  651. }
  652.  
  653.  
  654.  
  655.  
  656. //-----------------------------------------------------------------------------
  657. // Name:
  658. // Desc:
  659. //-----------------------------------------------------------------------------
  660. VOID CD3DCamera::SetViewParams( D3DXVECTOR3 &vEyePt, D3DXVECTOR3& vLookatPt,
  661.                                 D3DXVECTOR3& vUpVec )
  662. {
  663.     // Set attributes for the view matrix
  664.     m_vEyePt    = vEyePt;
  665.     m_vLookatPt = vLookatPt;
  666.     m_vUpVec    = vUpVec;
  667.     D3DXVec3Normalize( &m_vView, &(m_vLookatPt - m_vEyePt) );
  668.     D3DXVec3Cross( &m_vCross, &m_vView, &m_vUpVec );
  669.  
  670.     D3DXMatrixLookAtLH( &m_matView, &m_vEyePt, &m_vLookatPt, &m_vUpVec );
  671.     D3DXMatrixInverse( &m_matBillboard, NULL, &m_matView );
  672.     m_matBillboard._41 = 0.0f;
  673.     m_matBillboard._42 = 0.0f;
  674.     m_matBillboard._43 = 0.0f;
  675. }
  676.  
  677.  
  678.  
  679.  
  680. //-----------------------------------------------------------------------------
  681. // Name:
  682. // Desc:
  683. //-----------------------------------------------------------------------------
  684. VOID CD3DCamera::SetProjParams( FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
  685.                                 FLOAT fFarPlane )
  686. {
  687.     // Set attributes for the projection matrix
  688.     m_fFOV        = fFOV;
  689.     m_fAspect     = fAspect;
  690.     m_fNearPlane  = fNearPlane;
  691.     m_fFarPlane   = fFarPlane;
  692.  
  693.     D3DXMatrixPerspectiveFovLH( &m_matProj, fFOV, fAspect, fNearPlane, fFarPlane );
  694. }
  695.